interface PL0_Machine_Operation {
	public void perform(PL0_Machine machine_state);
}

public enum PL0_Machine_Function implements PL0_Machine_Operation {
	LIT // literal
	{
		public void perform(PL0_Machine machine_state) {
			machine_state.top_stack_pointer += 1;
			machine_state.s[machine_state.top_stack_pointer] = machine_state.instructionRegister.a;
		}
	},
	LOD {
		public void perform(PL0_Machine machine_state) {
			machine_state.top_stack_pointer += 1;
			machine_state.s[machine_state.top_stack_pointer] = machine_state.s[machine_state
					.base(machine_state.instructionRegister.l)
					+ machine_state.instructionRegister.a];
		}
	},
	STO {
		public void perform(PL0_Machine machine_state) {
			machine_state.s[machine_state
					.base(machine_state.instructionRegister.l)
					+ machine_state.instructionRegister.a] = machine_state.s[machine_state.top_stack_pointer];
			System.out.println(machine_state.s[machine_state.top_stack_pointer]);
			machine_state.top_stack_pointer -= 1;
		}
	},
	CAL //generate new block mark
	{
		public void perform(PL0_Machine machine_state) {
			machine_state.s[machine_state.top_stack_pointer + 1] = machine_state
					.base(machine_state.instructionRegister.l);
			machine_state.s[machine_state.top_stack_pointer + 2] = machine_state.base_pointer;
			machine_state.s[machine_state.top_stack_pointer + 3] = machine_state.program_counter;
			machine_state.base_pointer = machine_state.top_stack_pointer + 1;
			machine_state.program_counter = machine_state.instructionRegister.a;
		}
	},
	INC {
		public void perform(PL0_Machine machine_state) {
			System.out.println("trying perform in INC");
			machine_state.top_stack_pointer += machine_state.instructionRegister.a;
		}
	},
	JMP {
		public void perform(PL0_Machine machine_state) {
			machine_state.program_counter = machine_state.instructionRegister.a;
		}
	},
	JPC {
		public void perform(PL0_Machine machine_state) {
			if (machine_state.s[machine_state.top_stack_pointer] == 0)
				machine_state.program_counter = machine_state.instructionRegister.a;
			machine_state.top_stack_pointer -= 1;
		}
	},
	OPR // operator
	{
		public void perform(PL0_Machine machine_state) {
			switch (machine_state.instructionRegister.a) {
			case 0: { // return
				machine_state.top_stack_pointer = machine_state.base_pointer - 1;
				machine_state.program_counter = machine_state.s[machine_state.top_stack_pointer + 3];
				machine_state.base_pointer = machine_state.s[machine_state.top_stack_pointer + 2];
				break;
			}
			case 1: {
				machine_state.s[machine_state.top_stack_pointer] = -machine_state.s[machine_state.top_stack_pointer];
				break;
			}
			case 2: {
				machine_state.top_stack_pointer -= 1;
				machine_state.s[machine_state.top_stack_pointer] = machine_state.s[machine_state.top_stack_pointer]
						+ machine_state.s[machine_state.top_stack_pointer + 1];
				break;
			}
			case 3: {
				machine_state.top_stack_pointer -= 1;
				machine_state.s[machine_state.top_stack_pointer] = machine_state.s[machine_state.top_stack_pointer]
						- machine_state.s[machine_state.top_stack_pointer + 1];
				break;
			}
			case 4: {
				machine_state.top_stack_pointer -= 1;
				machine_state.s[machine_state.top_stack_pointer] = machine_state.s[machine_state.top_stack_pointer]
						* machine_state.s[machine_state.top_stack_pointer + 1];
				break;
			}
			case 5: {
				machine_state.top_stack_pointer -= 1;
				machine_state.s[machine_state.top_stack_pointer] = machine_state.s[machine_state.top_stack_pointer]
						/ machine_state.s[machine_state.top_stack_pointer + 1]; //	Pascal div
				break;
			}
			case 6: {
				//        	s[t] = ord(odd(s[t]));
				break;
			}
			case 8: {
				machine_state.top_stack_pointer -= 1;
				machine_state.s[machine_state.top_stack_pointer] = machine_state
						.ord(machine_state.s[machine_state.top_stack_pointer] == machine_state.s[machine_state.top_stack_pointer + 1]);
				break;
			}
			case 9: {
				machine_state.top_stack_pointer -= 1;
				//          s[t]= ord(s[t] != s[t+1]);
				break;
			}
			case 10: {
				machine_state.top_stack_pointer -= 1;
				//          s[t]= ord(s[t] < s[t+1]);
				break;
			}
			case 11: {
				machine_state.top_stack_pointer -= 1;
				//          s[t]= ord(s[t] >= s[t+1]);
				break;
			}
			case 12: {
				machine_state.top_stack_pointer -= 1;
				//          s[t]= ord(s[t] > s[t+1]);
				break;
			}
			case 13: {
				machine_state.top_stack_pointer -= 1;
				//          s[t]= ord(s[t] <= s[t+1]);
				break;
			}
			}
		}
	}
}